#-*-coding:utf-8-*-
'''
Created on 29.Oca.2010

@authors: Aşkın Yollu <askin@askin.ws>
          Erdem Artan <baDibere@gmail.com>
'''

import pisi
from xml.dom.minidom import Document
from noplatform import writePDX
import subprocess
from tempfile import gettempdir
import os

class Package:
    def __init__(self):
        self.repoDB = pisi.db.repodb.RepoDB()
        self.packageDB = pisi.db.packagedb.PackageDB()
        self.installDB = pisi.db.installdb.InstallDB()
        self.repos = self.repoDB.list_repos()

    def getPackageDeps(self, packages):
        # get deps
        deps = pisi.api.get_install_order(packages)

        deps_with_url = []

        for dep in deps:
            pkg = self.packageDB.get_package_repo(dep)
            # append, packagename, url, checksum
            deps_with_url.append((pkg[0].packageURI,
                                 "%s%s" % (self.getRepoURI(pkg[1]), pkg[0].packageURI),
                                 pkg[0].packageHash))
        return deps_with_url

    def getRepoURI(self, repo):
        repourl = self.repoDB.get_repo_url(repo)
        return repourl.replace("pisi-index.xml.bz2", "")

    def getXml(self, deps):
        # create minidom document
        doc = Document()

        # create root element
        root = doc.createElement("PDinstall")
        doc.appendChild(root)

        for dep in deps:
            # add package to root
            package = doc.createElement("package")
            root.appendChild(package)

            # add name to package
            name = doc.createElement("name")
            package.appendChild(name)
            text = doc.createTextNode(dep[0])
            name.appendChild(text)

            #add url to package
            packageurl = doc.createElement("packageurl")
            package.appendChild(packageurl)
            text = doc.createTextNode(dep[1])
            packageurl.appendChild(text)

            # add sha1sum to package
            sha1sum = doc.createElement("sha1sum")
            package.appendChild(sha1sum)
            text = doc.createTextNode(dep[2])
            sha1sum.appendChild(text)

        return doc.toprettyxml(indent="  ")

    # return upgradable package list
    def getUpdateList(self):
        if pisi.api.update_repos(self.repos):
            return pisi.api.list_upgradable()

    # Let's create XML that contains package information that will be downloaded
    def createXML(self, packages):
        deps = self.getPackageDeps(packages)
        xml  = self.getXml(deps)
        file = open("pisi-list.xml","w")
        file.write(xml)
        file.close()
        return True

    # create xml file, file include all installed package
    # with package name, version, release no
    def getInstalledPackages(self):
        # installed package with repo and info
        installed_package_with_repo = {}

        # installed package
        installed_packages = self.installDB.list_installed()

        ''' structure example
            {
                "contrib": [("pkg1, "1.0", "2"), ("pkg2", "3.5", "4")],
                "pardus-2009" : [("pkg3", "0.1", "2"), ("pkg3", "4.5", "1")]
            }
        '''
        for pkg in installed_packages:
            try:
                pkg_info = self.getInstalledPackageInfo(pkg)
                try:
                    installed_package_with_repo[pkg_info[0]].append(pkg_info[1])
                except KeyError:
                    installed_package_with_repo[pkg_info[0]] = [pkg_info[1]]
            except Exception, e:
                print "Exception : %s" % e

        # create minidom document
        doc = Document()

        # create root element
        root = doc.createElement("PDinstalledPackage")
        doc.appendChild(root)

        # get installed package xml
        for repo in installed_package_with_repo:
            repo_uri = self.repoDB.get_repo_url(repo).replace("pisi-index.xml.bz2", "")

            # add repo to root
            repo_tag = doc.createElement("Repo")
            repo_tag.setAttribute("repo", repo)
            repo_tag.setAttribute("repo_uri", repo_uri)

            root.appendChild(repo_tag)

            for package in installed_package_with_repo[repo]:
                name, version, release = package

                # add package to repo
                package = doc.createElement("package")
                repo_tag.appendChild(package)

                # add name to package
                name_tag = doc.createElement("name")
                package.appendChild(name_tag)
                text = doc.createTextNode(name)
                name_tag.appendChild(text)

                #add version to package
                version_tag = doc.createElement("version")
                package.appendChild(version_tag)
                text = doc.createTextNode(version)
                version_tag.appendChild(text)

                # add release to package
                release_tag = doc.createElement("release")
                package.appendChild(release_tag)
                text = doc.createTextNode(release)
                release_tag.appendChild(text)

        file = open(gettempdir() + "/installed-package.xml", "w")
        doc.writexml(file)

    # installed package info
    # for getInstallPackages method
    def getInstalledPackageInfo(self, package):
        pkg     = self.installDB.get_package(package)
        repo    = self.packageDB.get_package_repo(package)

        name    = package
        version = pkg.version
        release = pkg.release

        return [repo[1], (name, version, release)]

    '''
    pisi api kullanılarak güncellenecek paketleri bularak
    pdx dosyaları oluşturmak için kullanılıyor.
    '''
    def writeUpdatedPackages(self, use_delta):
        # Güncel paketlerin alıması
        print use_delta
        updates = []
        upgradable = pisi.api.get_install_order(pisi.api.list_upgradable())
        repo_urls = self.repoDB.list_repo_urls()

        repos = {}

        for i in xrange(len(self.repos)):
            repos[self.repos[i]] = repo_urls[i]

        for pkg in upgradable:
          package = self.packageDB.get_package(pkg)
          if use_delta:
              try:
                #from pisi's atomicoperations.py
                #bakalım delta paketi var mıymış
                idb = pisi.db.installdb.InstallDB()
                (version, release, build, distro, distro_release) = idb.get_version_and_distro_release(package.name)
                delta = package.get_delta(buildFrom=build)
                if delta:
                  package.packageURI = delta.packageURI
                  package.packageHash = delta.packageHash
              except:
                pass

          url = "%s%s" % (self.getRepoURI(self.packageDB.get_package_repo(pkg)[1]), package.packageURI)
          pkgdict = {"name" : pkg, "repo" : self.packageDB.get_package_repo(pkg)[1], "url" : url , "hash" : package.packageHash}
          updates.append(pkgdict)

        writePDX(updates, repos, gettempdir() + "/updates.pdx")

    '''
    sistemde ekli olan repoları listeler
    dizi içinde sözlük dönrürür.
    [{"repo" : "pardus-2009", "url" : "http://packages.pardus.org.tr/pardus-2009/"},
     {"repo" : "contrib", "url" : "http://paketler.pardus.org.tr/contrib-2009/"}]
    '''
    def listRepos(self):
        repos = [];
        for i in pisi.api.list_repos():
            repos.append({"repo" : i, "url" : self.getRepoURI(i)})

        return repos

    def __auth_cmd(self):
        auth_type = ""
        if os.path.isfile("/usr/kde/4/lib/kde4/libexec/kdesu"):
            return "/usr/kde/4/lib/kde4/libexec/kdesu -t \"%s\""
        elif os.path.isfile("/usr/bin/gksudo"):
            return "gksudo \"%s\""
        elif os.path.isfile("/usr/bin/xterm"):
            return "xterm -e sudo %s"
        else:
            return False

    '''
    Parametre olarak geçirilen komutu
    Kabukta çalıştırır, komut çıktısını ve başarılı olup olmadığını döndürür
    Başarılı bir işlem
    (True, "Hello World")
    Başarısız bir işlem
    (False, "bla bla bla")
    root=True parametresiyle root olarak çalıştırır
    '''
    def call_command(self, command, root=False):
        if root:
            cmd = self.__auth_cmd() % command
        else:
            cmd = command
        # Çıktıları Gösterme
        out = subprocess.PIPE
        p = subprocess.Popen(cmd, shell=True, stdout=out)
        out, err = p.communicate()

        if p.returncode < 0:
            return (False, out)
        else:
            return (True, out)

    '''
    Depo indeksini günceller,
    İnternete ihtiyaç duyar
    Root yetkisi ister(kdesu)
    '''
    def update_repo(self):
        rt = self.call_command("pisi ur", root=True)
        return rt

    '''
    Paketleri günceller,
    İnternet bağlantısı gerektirmez,
    Paketlerin yeni sürümleri /var/cache/pisi/packages
       dizinine öncedan atılması gerekir
    '''
    def update_system(self):
        rt = self.call_command("pisi up --bypass-update-repo", root=True)
        return rt

    '''
    Belli bir dizindeki pisi paketlerini
    /var/cache/pisi/packages dizinine taşır
    '''
    def move_packages(self, source):
        cmd = "mv %s /var/cache/pisi/packages" % os.path.join(source, "*pisi")
        rt = self.call_command(cmd, root=True)
        return rt
